#pragma once

#include "IXFileSystem.h"
#include "IXFileReader.h"
#include "XBaseObjImpl.h"

struct stFSData
{
    XString         strName;
    XString         strBundle;
    XString         strPath;
    IXFileReader*   pReader;
};

__inline bool operator < (const stFSData& data1, const stFSData& data2)
{
    if(data1.pReader != data2.pReader)
        return (DWORD)data1.pReader < (DWORD)data2.pReader;
    else if(data1.strName != data2.strName)
        return data1.strName < data2.strName;
    else if(data1.strPath != data2.strPath)
        return data1.strPath < data2.strPath;
}

__inline bool operator == (const stFSData& data, const XString& strName)
{
    if(data.strName == strName)
        return true;
    return false;
}

class CXFileSystemImpl : public CXBaseObjImpl<IXFileSystem>
{
    typedef CXBaseObjImpl<IXFileSystem> superclass;
    DEF_SKIN_CLASS_SINGLE_INTF(CXFileSystemImpl,
        superclass,
        gs_strGuidXSkin,
        IXFileSystem,
        eIntf_Singleton);
public:
    CXFileSystemImpl();
    virtual ~CXFileSystemImpl();

public:
    // IXFileSystem
    virtual HRESULT STDMETHODCALLTYPE   put_XNCFile(IN LPCTSTR szXNCFilePath);
    virtual HRESULT STDMETHODCALLTYPE   LoadFile(IN LPCTSTR szXNC, OUT IXFixedBuffer** pData);
    virtual HRESULT STDMETHODCALLTYPE   IsValidXNC(IN LPCTSTR szXNC, OUT BOOL* pbXNC);
    virtual HRESULT STDMETHODCALLTYPE   ParserXNC(IN LPCTSTR szXNC, OUT BSTR* pbstrRootPath, OUT BSTR* pbstrRelativePath);
    virtual void    STDMETHODCALLTYPE   put_LoadFromRes(IN BOOL bLoadFromRes);
    virtual BOOL    STDMETHODCALLTYPE   get_LoadFromRes();
    virtual BOOL    STDMETHODCALLTYPE   IsFileExists(IN LPCTSTR szFilePath);
    virtual BOOL    STDMETHODCALLTYPE   IsFolderExists(IN LPCTSTR szFolderPath);

    // IXBaseObj
    virtual void    STDMETHODCALLTYPE   OnFinalRelease();

protected:
    void    ReleaseData();
    IXFileReader* GetFileReader(IN LPCTSTR szXNC, OUT XString& strRelativePath);

    BOOL    TranslateXNC(IN LPCTSTR szXNC, OUT XString& strBundle, OUT XString& strPath);
    BOOL    TranslateRealFS(IN LPCTSTR szXNC, OUT XString& strBundle, OUT XString& strPath);

    HRESULT ParseXNC(IN LPCTSTR szXNC);

    HRESULT LoadFileFromXFile(IN LPCTSTR szXNC, OUT IXFileMapBuffer** pData);
    HRESULT LoadFileFromRealFS(IN LPCTSTR szXNC, OUT IXFileMapBuffer** pData);
    HRESULT LoadFileFromExeRes(IN LPCTSTR szXNC, OUT IXFixedBuffer** pData);

    BOOL    GetFSData(LPCTSTR szXNC, XString& strRelativePath, stFSData*& pData);

    BOOL    IsExeResPath(LPCTSTR szXNC);
    BOOL    ParserResPath(IN LPCTSTR szXNC, OUT XString& strResType, OUT XString& strResName);
    LPCTSTR StringToResType(LPCTSTR szType);
    LPCTSTR FilExtToString(LPCTSTR szFileExit);

    XString FilterXNC(IN LPCTSTR szXNC);

protected:
    typedef std::vector<stFSData>    XFileContainer;
    XFileContainer  m_XFileContainer;

    BOOL            m_bLoadFromRes;
    XString         m_strRootPath;
    XString         m_strBundleConfigPath;
};

